package com.hwg;

/**
 * 死锁模拟器 - 用于模拟不同类型的死锁情况，测试死锁检测工具
 */
public class DeadlockSimulator {
    // 用于演示的锁对象
    private static final Object LOCK_A = new Object();
    private static final Object LOCK_B = new Object();
    private static final Object LOCK_C = new Object();

    public static void main(String[] args) {
        System.out.println("死锁模拟器已启动 - 进程ID: " + ProcessHandle.current().pid());
        System.out.println("请使用JavaDeadlockDetector程序检测此进程的死锁情况");

        // 打印选项菜单
        System.out.println("\n可用的死锁模拟类型:");
        System.out.println("1. 简单的双线程死锁");
        System.out.println("2. 三线程循环死锁");
        System.out.println("3. 同步方法死锁");
        System.out.println("4. 嵌套同步死锁");

        java.util.Scanner scanner = new java.util.Scanner(System.in);
        System.out.print("\n请选择要模拟的死锁类型(1-4): ");
        int choice = 1;

        try {
            choice = Integer.parseInt(scanner.nextLine().trim());
        } catch (NumberFormatException e) {
            System.out.println("输入无效，默认使用选项1");
        }

        switch (choice) {
            case 1:
                simulateSimpleDeadlock();
                break;
            case 2:
                simulateCircularDeadlock();
                break;
            case 3:
                simulateSynchronizedMethodDeadlock();
                break;
            case 4:
                simulateNestedSynchronizationDeadlock();
                break;
            default:
                System.out.println("选项无效，默认使用选项1");
                simulateSimpleDeadlock();
        }

        // 保持程序运行，以便可以检测到死锁
        System.out.println("\n死锁已创建，程序将保持运行状态");
        System.out.println("按Enter键退出程序");

        try {
            scanner.nextLine();
        } catch (Exception e) {
            // 忽略异常
        }
    }

    /**
     * 模拟简单的双线程死锁
     * 线程1：先获取锁A，再尝试获取锁B
     * 线程2：先获取锁B，再尝试获取锁A
     */
    private static void simulateSimpleDeadlock() {
        System.out.println("\n正在模拟简单的双线程死锁...");

        Thread thread1 = new Thread(() -> {
            synchronized (LOCK_A) {
                System.out.println("线程1获取了锁A");
                try {
                    // 让线程2有机会获取锁B
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }

                System.out.println("线程1尝试获取锁B");
                synchronized (LOCK_B) {
                    System.out.println("线程1获取了锁B");
                }
            }
        }, "简单死锁-线程1");

        Thread thread2 = new Thread(() -> {
            synchronized (LOCK_B) {
                System.out.println("线程2获取了锁B");
                try {
                    // 让线程1有机会获取锁A
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }

                System.out.println("线程2尝试获取锁A");
                synchronized (LOCK_A) {
                    System.out.println("线程2获取了锁A");
                }
            }
        }, "简单死锁-线程2");

        thread1.start();
        thread2.start();
    }

    /**
     * 模拟三线程循环死锁
     * 线程1：先获取锁A，再尝试获取锁B
     * 线程2：先获取锁B，再尝试获取锁C
     * 线程3：先获取锁C，再尝试获取锁A
     */
    private static void simulateCircularDeadlock() {
        System.out.println("\n正在模拟三线程循环死锁...");

        Thread thread1 = new Thread(() -> {
            synchronized (LOCK_A) {
                System.out.println("线程1获取了锁A");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }

                System.out.println("线程1尝试获取锁B");
                synchronized (LOCK_B) {
                    System.out.println("线程1获取了锁B");
                }
            }
        }, "循环死锁-线程1");

        Thread thread2 = new Thread(() -> {
            synchronized (LOCK_B) {
                System.out.println("线程2获取了锁B");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }

                System.out.println("线程2尝试获取锁C");
                synchronized (LOCK_C) {
                    System.out.println("线程2获取了锁C");
                }
            }
        }, "循环死锁-线程2");

        Thread thread3 = new Thread(() -> {
            synchronized (LOCK_C) {
                System.out.println("线程3获取了锁C");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }

                System.out.println("线程3尝试获取锁A");
                synchronized (LOCK_A) {
                    System.out.println("线程3获取了锁A");
                }
            }
        }, "循环死锁-线程3");

        thread1.start();
        thread2.start();
        thread3.start();
    }

    /**
     * 模拟同步方法死锁
     * 两个线程分别以不同顺序调用两个同步方法
     */
    private static void simulateSynchronizedMethodDeadlock() {
        System.out.println("\n正在模拟同步方法死锁...");

        final SynchronizedMethods obj = new SynchronizedMethods();

        Thread thread1 = new Thread(() -> {
            obj.methodA();
        }, "同步方法死锁-线程1");

        Thread thread2 = new Thread(() -> {
            obj.methodB();
        }, "同步方法死锁-线程2");

        thread1.start();
        thread2.start();
    }

    /**
     * 用于同步方法死锁演示的类
     */
    static class SynchronizedMethods {
        public synchronized void methodA() {
            System.out.println(Thread.currentThread().getName() + " 进入方法A");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }

            System.out.println(Thread.currentThread().getName() + " 尝试调用方法B");
            methodB();
        }

        public synchronized void methodB() {
            System.out.println(Thread.currentThread().getName() + " 进入方法B");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }

            System.out.println(Thread.currentThread().getName() + " 尝试调用方法A");
            methodA();
        }
    }

    /**
     * 模拟嵌套同步死锁
     * 两个线程在不同对象上嵌套同步
     */
    private static void simulateNestedSynchronizationDeadlock() {
        System.out.println("\n正在模拟嵌套同步死锁...");

        final NestedResource resource1 = new NestedResource("资源1");
        final NestedResource resource2 = new NestedResource("资源2");

        Thread thread1 = new Thread(() -> {
            resource1.operateOnResource(resource2);
        }, "嵌套同步死锁-线程1");

        Thread thread2 = new Thread(() -> {
            resource2.operateOnResource(resource1);
        }, "嵌套同步死锁-线程2");

        thread1.start();
        thread2.start();
    }

    /**
     * 用于嵌套同步死锁演示的资源类
     */
    static class NestedResource {
        private final String name;

        public NestedResource(String name) {
            this.name = name;
        }

        public synchronized void operateOnResource(NestedResource other) {
            System.out.println(Thread.currentThread().getName() + " 获取了 " + name + " 的锁");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }

            System.out.println(Thread.currentThread().getName() + " 尝试获取 " + other.name + " 的锁");
            other.executeOperation();
        }

        public synchronized void executeOperation() {
            System.out.println(Thread.currentThread().getName() + " 执行了 " + name + " 上的操作");
        }
    }
}